package com.shchekoldin.juliet.packager.core;

import com.shchekoldin.juliet.packager.utils.FileContentReader;
import com.shchekoldin.juliet.packager.xml.ProjectElement;
import jargs.gnu.CmdLineParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ProjectFactory {

    private final String PARAM_PREFIX = "--";

    private final String PROJECT_OPTION_NAME = "project";

    private static ProjectFactory instance = null;

    private static final Logger logger = LoggerFactory.getLogger(ProjectFactory.class);

    // -------------------------------------------------------
    // -                      INSTANCE                       -
    // -------------------------------------------------------

    public static ProjectFactory getInstance() {
        if (instance == null) instance = new ProjectFactory();
        return instance;
    }

    private ProjectFactory() { }

    // -------------------------------------------------------
    // -                        LOGIC                        -
    // -------------------------------------------------------

    private StringReader bindCommandLineParams(Map<String, String> cmdLineParserOptionsHash) {
        String projectXmlFile = cmdLineParserOptionsHash.get(PROJECT_OPTION_NAME);
        String projectSource = null;

        try {
            projectSource = FileContentReader.getInstance().run(projectXmlFile);
        } catch (IOException e) {
            logger.error("Can't read project xml file", e);
            Packager.getInstance().exit();
        }

        String bindedProjectSource = projectSource;

        for (Map.Entry<String, String> entry : cmdLineParserOptionsHash.entrySet()) {
            bindedProjectSource = bindedProjectSource.replace("${" + entry.getKey() + "}", entry.getValue());
        }

        return new StringReader(bindedProjectSource);
    }

    private ProjectElement loadProject(StringReader projectSource) {
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(ProjectElement.class);
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

            return (ProjectElement) unmarshaller.unmarshal(projectSource);
        } catch (Exception e) {
            logger.error("Can't parse project xml file", e);
            Packager.getInstance().exit();
        }

        return null;
    }

    //
    // API
    //

    public ProjectElement run(String[] args) {
        List<CmdLineParser.Option> cmdLineParserOptions = new ArrayList<CmdLineParser.Option>();
        CmdLineParser cmdLineParser = new CmdLineParser();
        Map<String, String> cmdLineParserOptionsHash = new HashMap<String, String>();

        for (String paramName : args) {
            if (paramName.indexOf(PARAM_PREFIX) != 0) continue;
            String fixedParamName = paramName.replace(PARAM_PREFIX, "");
            cmdLineParserOptions.add(cmdLineParser.addStringOption(fixedParamName));
        }

        try {
            cmdLineParser.parse(args);
        } catch (Exception e) {
            logger.error("Can't parse packager command line args", e);
            Packager.getInstance().exit();
        }

        for (CmdLineParser.Option option : cmdLineParserOptions) {
            cmdLineParserOptionsHash.put(option.longForm(), (String) cmdLineParser.getOptionValue(option));
        }

        return loadProject(bindCommandLineParams(cmdLineParserOptionsHash));
    }

}
